#include "ptwrap.hpp"
#include <stdio.h>
#include <unistd.h>

// the manual-reset variety
// [[ex03af]]
// DEBUG descr A simple-minded manual-reset event.
class event
{
public:
	event(bool signaled = false) :
		signaled_(signaled)
	{ }

	int wait()
	{
		pw::lockmutex lm(cond_);
		if (signaled_)
			return 0;
		cond_.wait();
		return 0;
	}
	int trywait()
	{
		pw::lockmutex lm(cond_);
		if (signaled_)
			return 0;
		return ETIMEDOUT;
	}
	int timedwait(const struct timespec &abstime)
	{
		pw::lockmutex lm(cond_);
		if (signaled_)
			return 0;
		if (cond_.timedwait(abstime) == ETIMEDOUT)
			return ETIMEDOUT;
		return 0;
	}
	int signal()
	{
		pw::lockmutex lm(cond_);
		signaled_ = true;
		cond_.broadcast();
		return 0;
	}
	int reset()
	{
		pw::lockmutex lm(cond_);
		signaled_ = false;
	}
	int pulse()
	{
		pw::lockmutex lm(cond_);
		signaled_ = false;
		cond_.broadcast();
		return 0;
	}

protected:
	// contains both condition variable and a mutex
	pw::pmcond cond_; 
	// event is in the signaled state
	bool signaled_; 
};
// END

// DEBUG {

event ev;

class waiter : public pw::pwthread
{
public:
	// auto-start on construction and stop before destruction
	waiter()
	{
		start();
	}
	~waiter()
	{
		join();
	}
	void *execute()
	{
		ev.wait();
		fprintf(stderr, "wait succeeded\n");
		return 0;
	}
};

int main()
{
	ev.pulse();
	if (ev.trywait() == ETIMEDOUT)
		fprintf(stderr, "trywait failed as expected\n");

	{
		waiter w1;
		ev.signal();
		waiter w2;
	}
	fprintf(stderr, "---\n");
	{
		waiter w1, w2, w3;
		usleep(100*1000);
		ev.pulse();
	}

	if (ev.trywait() == ETIMEDOUT)
		fprintf(stderr, "trywait failed as expected\n");
	ev.signal();
	ev.signal();
	if (ev.trywait() == 0)
		fprintf(stderr, "trywait succeeded as expected\n");
	ev.reset();
	if (ev.trywait() == ETIMEDOUT)
		fprintf(stderr, "trywait failed as expected\n");

	struct timespec endtime;
	clock_gettime(CLOCK_REALTIME, &endtime); // the current time
	if (ev.timedwait(endtime) == ETIMEDOUT)
		fprintf(stderr, "timedwait failed as expected\n");
	ev.signal();
	if (ev.timedwait(endtime) == 0)
		fprintf(stderr, "timedwait succeeded as expected\n");
	return 0;
}
// DEBUG }
/* Sample output:

trywait failed as expected
wait succeeded
wait succeeded
---
wait succeeded
wait succeeded
wait succeeded
trywait failed as expected
trywait succeeded as expected
trywait failed as expected
timedwait failed as expected
timedwait succeeded as expected

*/
